/********************************************************************************
 * Copyright(c) 2020-2025 VINCENT_WY All rights reserved.
 * - Filename
 * - Author  Vincent
 * - Version V1.0.0
 * - Date    2023/09/21
 * - Brief
 * - FunctionList:
 ******************************************************************************
 * History:
 *
 *
 *
 ******************************************************************************
 */

#include "Replayer.hpp"
#include "nlohmann/json.hpp"
#include <fstream>
#include "NoBufferedReplayImpl.hpp"
#include "log.h"

using njson = nlohmann::json;

const static char *TAG("Replayer");
Replayer::Replayer(const std::string &cfg)
    : _cfgFile(cfg)
{
  LOGI(TAG, "~~~~");
}

Replayer::~Replayer() { LOGI(TAG, "~~~~"); }
void Replayer::start()
{
  creatReplayImpl();
  for (auto &&impl : _frameImpl)
  {
    impl->start(nullptr, _allFrameStartTime);
  }

  _loopThread = std::make_unique<std::thread>(&Replayer::loop, this);
  LOGI(TAG, "Start ...");
}
void Replayer::stop()
{
  LOGI(TAG, "stop+");
  _isExit = true;
  if (_loopThread != nullptr && _loopThread->joinable())
  {
    _loopThread->join();
  };

  for (auto &&impl : _frameImpl)
  {
    impl->stop();
  }
  LOGI(TAG, "stop-");
}

void Replayer::creatReplayImpl()
{
  std::fstream cfgStream{_cfgFile};
  std::vector<long long int> frameStartTime;
  njson cfg;
  try
  {
    cfgStream >> cfg;
    _repeat = cfg["player"]["repeat"].get<bool>();
    _rootPath = cfg["player"]["path"].get<std::string>();
    auto source = cfg.at("source");
    // lidar
    for (auto &lidar : source)
    {
      auto id = lidar.at("lidar_id").get<int>();
      auto port = lidar.at("lidar_port").get<int>();
      auto player = std::make_shared<NoBufferedReplayImpl>(id, _rootPath);

      if (player->getFirstFrameTm() < 0)
        continue;
      frameStartTime.emplace_back(player->getFirstFrameTm());
      _frameImpl.push_back(player);
    }

    if (frameStartTime.empty())
      return;
    std::sort(frameStartTime.begin(), frameStartTime.end());
    _allFrameStartTime = frameStartTime.front() -1000000; //100ms
    LOG_I(TAG, "all frame start time: {}", std::to_string(_allFrameStartTime));
  }
  catch (const std::exception &e)
  {
    LOG_E(TAG, "get config from {},error {} ...", _cfgFile.c_str(), e.what());
    return;
  }
}
void Replayer::loop()
{
  while (!_isExit)
  {
    _repeatCount = 0;
    for (auto &&impl : _frameImpl)
    {
      if (impl->isComplete())
      {
        _repeatCount++;
      }
    }

    // 开启重复，每一路都回灌完成，则重新回灌
    if (_repeat && (_repeatCount == (int)_frameImpl.size()))
    {
      _repeatCount = 0;
      LOGI(TAG, "will do repeat,please wait for 5 second ...");
      std::this_thread::sleep_for(std::chrono::seconds(5));

      for (auto &&impl : _frameImpl)
      {
        impl->doRepeat();
      }
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
  }
}
